﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Yonkly.Models;
using Yonkly.Utility;
using JsonResult = System.Web.Mvc.JsonResult;

namespace Yonkly.Controllers
{
    public class GroupController : BaseController
    {
        public ViewResult Index(string Id, int? page)
        {
            page = page ?? 0;
            ViewData["IsGroup"] = true;
            return View("Index", GetGroupViewData(Id, (int)page));
        }

        public ViewResult Edit(string Id)
        {
            ViewData["IsGroup"] = true;
            return View("Edit", GetGroupViewData(Id, 0));
        }

        public ActionResult New()
        {
            if (!IsUserAuthenticated)
            {
                return RedirectToAction("Index", "Home");
            }
            return View("New", GetBaseViewData());
        }

        public ViewResult List()
        {
            return View("list", GetBaseViewData());
        }

        public ViewResult MySettings(string Id)
        {
            return View("MySettings", GetGroupViewData(Id, 0));
        }

        public ViewResult Conversation(string Id, long messageId, int? page)
        {
            return View("Conversation", GetConversationData(Id, messageId, page));
        }

        #region Json Actions

        public JsonResult Destroy(long groupId)
        {
            var data = new JsonData();
            try
            {
                if (!IsUserAuthenticated)
                {
                    data.errorMessage = "You are not logged in.  Please login before you can create a group.";
                    data.isSuccessful = false;
                    return Json(data);
                }
                using (var dc = new YonklyDataContext())
                {
                    //make sure that you are the owner
                    if (
                        dc.GroupMembers.Count(
                            gm =>
                            gm.GroupId == groupId
                            && gm.UserId == LoggedInUserId
                            && gm.Role == (int)GroupMemberRoles.Owner
                            ) == 0)
                    {
                        data.errorMessage = "You are not authorized to delete this group";
                        data.isSuccessful = false;
                        return Json(data);
                    }

                    DbTransaction trans = null;
                    try
                    {
                        dc.Connection.Open();
                        trans = dc.Connection.BeginTransaction();
                        dc.Transaction = trans;
                        //delete members
                        var members = dc.GroupMembers.Where(mem => mem.GroupId == groupId);
                        dc.GroupMembers.DeleteAllOnSubmit(members);

                        //delete messages
                        var messages = dc.GroupMessages.Where(mes => mes.GroupId == groupId);
                        dc.GroupMessages.DeleteAllOnSubmit(messages);

                        //delete group
                        Group g = dc.Groups.First(gr => gr.Id == groupId);
                        dc.Groups.DeleteOnSubmit(g);

                        dc.SubmitChanges();
                        trans.Commit();
                        data.isSuccessful = true;
                        return Json(data);
                    }
                    catch (Exception ex)
                    {
                        if (trans != null) trans.Rollback();
                        data.errorMessage = "An unknown error occurred while deleting.";
                        data.errorMessage = ex.Message;
                        data.isSuccessful = false;
                        return Json(data);
                    }
                    finally
                    {
                        if (dc.Connection.State == ConnectionState.Open)
                            dc.Connection.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                data.errorMessage = "An unknown error occurred while deleting.";
                data.errorMessage = ex.Message;
                data.isSuccessful = false;
                return Json(data);
            }
        }

        public JsonResult Update(long groupId, string url, string name,
                                 string about, int groupVisibility,
                                 int groupMembership, bool isAutoApprove,
                                 bool membersCanInvite)
        {
            var data = new JsonData();
            if (!IsUserAuthenticated)
            {
                data.errorMessage = "You are not logged in.  Please login before you can create a group.";
                data.isSuccessful = false;
                return Json(data);
            }
            //make sure url is not part of any route names
            if (!IsValidUrl(url))
            {
                data.errorMessage = "Invalid Url, choose a different one.";
                data.isSuccessful = false;
                return Json(data);
            }

            using (var dc = new YonklyDataContext())
            {
                //make sure that you are an admin or owner
                if (
                    dc.GroupMembers.Count(
                        gm =>
                        gm.GroupId == groupId && gm.UserId == LoggedInUserId && gm.Role == (int)GroupMemberRoles.Owner) ==
                    0)
                {
                    data.errorMessage = "You are not authorized to edit this group";
                    data.isSuccessful = false;
                    return Json(data);
                }

                try
                {
                    Group g = dc.Groups.First(gr => gr.Id == groupId);
                    g.Name = name;
                    g.About = about;
                    g.Membership = groupMembership;
                    g.Visibility = groupVisibility;
                    g.IsAutoApprove = isAutoApprove;
                    g.CanMembersInvite = membersCanInvite;
                    g.ModifiedOn = DateTime.Now.ToUniversalTime();

                    dc.SubmitChanges();
                    data.isSuccessful = true;
                }
                catch (Exception)
                {
                    data.isSuccessful = false;
                    data.errorMessage = "Unknown error while saving";
                }
            }
            return Json(data);
        }

        public JsonResult Create(string url, string name,
                                 string about, int groupVisibility,
                                 int groupMembership, bool isAutoApprove,
                                 bool membersCanInvite)
        {
            var data = new JsonData();
            //todo make sure user is logged in
            if (!IsUserAuthenticated)
            {
                data.errorMessage = "You are not logged in.  Please login before you can create a group.";
                data.isSuccessful = false;
                return Json(data);
            }
            //make sure url is not part of any route names
            if (!IsValidUrl(url))
            {
                data.errorMessage = "Invalid Url, choose a different one.";
                data.isSuccessful = false;
                return Json(data);
            }

            using (var dc = new YonklyDataContext())
            {
                if (dc.Groups.Count(g => g.Url.ToLower() == url.ToLower()) > 0)
                {
                    data.errorMessage = "Url is already taken.";
                    data.isSuccessful = false;
                }
                else
                {
                    try
                    {
                        Group g = new Group();
                        g.Url = url;
                        g.Name = name;
                        g.About = about;
                        g.Membership = groupMembership;
                        g.Visibility = groupVisibility;
                        g.IsAutoApprove = isAutoApprove;
                        g.CanMembersInvite = membersCanInvite;
                        g.CreatedOn = DateTime.Now.ToUniversalTime();
                        g.ModifiedOn = DateTime.Now.ToUniversalTime();
                        dc.Groups.InsertOnSubmit(g);

                        var m = new GroupMember
                                    {
                                        Group = g,
                                        UserId = LoggedInUserId,
                                        Role = ((int)GroupMemberRoles.Owner),
                                        Status = ((int)GroupMemberStatuses.Approved),
                                        NotifyOnJoin = true,
                                        NotifyOnLeave = true,
                                        NotifyOnMessage = true,
                                        NotifyOnReply = true,
                                        NotifyOnPending = true
                                    };
                        dc.GroupMembers.InsertOnSubmit(m);

                        dc.SubmitChanges();
                        data.isSuccessful = true;
                    }
                    catch (Exception)
                    {
                        data.isSuccessful = false;
                        data.errorMessage = "Unknown error while saving";
                    }
                }
            }
            return Json(data);
        }

        public JsonResult Approve(int groupId, Guid userId)
        {
            return UpdateMemberStatus(groupId, userId, GroupMemberStatuses.Approved);
        }

        public JsonResult Reject(int groupId, Guid userId)
        {
            return UpdateMemberStatus(groupId, userId, GroupMemberStatuses.Rejected);
        }

        public JsonResult CheckAvailability(string url)
        {
            bool isAvailable;
            if (!IsValidUrl(url))
            {
                isAvailable = false;
            }
            else
            {
                using (YonklyDataContext dc = new YonklyDataContext())
                {
                    if (dc.Groups.Count(g => g.Url.ToLower() == url.ToLower()) > 0)
                    {
                        isAvailable = false;
                    }
                    else isAvailable = true;
                }
            }
            return Json(new { isAvailable });
        }

        public JsonResult JoinSubmit(int groupId, Guid userId)
        {
            var data = new JsonData();
            //make sure user is not already a member
            using (YonklyDataContext dc = new YonklyDataContext())
            {
                if (dc.GroupMembers.Count(gm => gm.GroupId == groupId && gm.UserId == userId) > 0)
                {
                    data.isSuccessful = false;
                    data.errorMessage = "You are already a memeber";
                }
                else
                {
                    try
                    {
                        var g = dc.Groups.Where(group => group.Id == groupId).First();
                        var member = new GroupMember
                                         {
                                             GroupId = groupId,
                                             UserId = userId,
                                             Role = ((int)GroupMemberRoles.Member),
                                             NotifyOnJoin = true,
                                             NotifyOnLeave = true,
                                             NotifyOnMessage = true,
                                             NotifyOnReply = true,
                                             NotifyOnPending = false
                                         };
                        if (g.IsAutoApprove)
                            member.Status = (int)GroupMemberStatuses.Approved;
                        else
                            member.Status = (int)GroupMemberStatuses.Pending;
                        dc.GroupMembers.InsertOnSubmit(member);
                        dc.SubmitChanges();
                        data.isSuccessful = true;
                        switch (member.Status)
                        {
                            case (int)GroupMemberStatuses.Approved:
                                SendApprovedEmailToJoiner(g, LoggedInUserName, System.Web.Security.Membership.GetUser().Email);
                                SendNewMemberNotification(g, LoggedInUserName);
                                break;
                            case (int)GroupMemberStatuses.Pending:
                                SendPendingApprovalNotification(g, LoggedInUserName);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Utility.Utils.Log(ex);
                        data.isSuccessful = false;
                        data.errorMessage = "Failed to join - unknown error";
                    }
                }
            }

            return Json(data);
        }

        public JsonResult SaveSettings(string id, long groupId, Guid userId,
            bool notifyOnMessage, bool notifyOnReply,
            bool notifyOnJoin, bool notifyOnLeave, bool notifyOnPending)
        {
            var data = new JsonData();
            try
            {
                using (var dc = new YonklyDataContext())
                {
                    var mem = dc.GroupMembers.Where(gm => gm.GroupId == groupId &&
                                                            gm.UserId == userId).Single();
                    mem.NotifyOnJoin = notifyOnJoin;
                    mem.NotifyOnLeave = notifyOnLeave;
                    mem.NotifyOnMessage = notifyOnMessage;
                    mem.NotifyOnReply = notifyOnReply;
                    if (mem.Role == (int)GroupMemberRoles.Owner)
                    {
                        //only owners can be notified of pending requests
                        mem.NotifyOnPending = notifyOnPending;
                    }
                    dc.SubmitChanges();
                    data.isSuccessful = true;
                }
            }
            catch (Exception)
            {
                data.isSuccessful = false;
                data.errorMessage = "Unkwon error occurred while saving";
                throw;
            }

            return Json(data);
        }

        public JsonResult LeaveSubmit(int groupId, Guid userId)
        {
            var data = new JsonData();
            //make sure user is not already a member
            using (var dc = new YonklyDataContext())
            {
                if (dc.GroupMembers.Count(gm => gm.GroupId == groupId && gm.UserId == userId) < 0)
                {
                    data.isSuccessful = false;
                    data.errorMessage = "You are not a member of this group.";
                }
                else
                {
                    try
                    {
                        var groupMember = dc.GroupMembers.Where(gm => gm.GroupId == groupId && gm.UserId == userId);
                        dc.GroupMembers.DeleteAllOnSubmit(groupMember);
                        dc.SubmitChanges();
                        data.isSuccessful = true;
                    }
                    catch (Exception ex)
                    {
                        Utils.Log(ex);
                        data.isSuccessful = false;
                        data.errorMessage = "Failed to leave - unknown error";
                    }
                }
            }

            if (data.isSuccessful)
                SendMemberLeaveNotification(groupId, userId);

            return Json(data);
        }

        public JsonResult PostMessage(long groupId, string message, long? parentId)
        {
            var data = new JsonData();
            var groupViewData = GetGroupViewData(groupId, 0);
            if (!groupViewData.CanPostMessage())
            {
                data.errorMessage = "You don't have permission to post to this group.";
                data.isSuccessful = false;
                return Json(data);
            }

            try
            {
                long messageId;
                using (var dc = new YonklyDataContext())
                {
                    var groupMessage = new GroupMessage
                                           {
                                               GroupId = groupId,
                                               ParentId = parentId,
                                               Text = message,
                                               SenderId = LoggedInUserId,
                                               CreatedOn = DateTime.Now.ToUniversalTime(),
                                               ModifiedOn = DateTime.Now.ToUniversalTime()
                                           };
                    dc.GroupMessages.InsertOnSubmit(groupMessage);
                    dc.SubmitChanges();
                    messageId = groupMessage.MessageId;
                }
                data.isSuccessful = true;
                if (parentId != null)
                {
                    //SendMessageReplyNotification();
                }
                SendNewMessageNotification(groupId, message, messageId);
                return Json(data);
            }
            catch (Exception)
            {
                data.isSuccessful = false;
                data.errorMessage = "Unknown error occurred while posting message";
                return Json(data);
            }
        }

        public JsonResult Reply(long groupId, long messageId, string message)
        {
            //var data = new JsonData();
            //data.errorMessage = "not implemented";
            return PostMessage(groupId, message, messageId);
            //return Json(data);


        }

        public JsonResult DeleteMessage(long messageId)
        {
            var result = new JsonData();
            try
            {
                //delete message from database
                //make sure the user has the right to delete
                using (var dc = new YonklyDataContext())
                {
                    //get the message
                    var message = dc.GroupMessages.Where(m => m.MessageId == messageId
                                                         && m.SenderId == LoggedInUserId).First();

                    if (message != null)
                    {
                        if (dc.ViewGroupMessages.First(m => m.MessageId == messageId).ChildrenCount > 0)
                        {
                            result.isSuccessful = false;
                            result.errorMessage = "You cannot delete messages that have been replied to.";
                        }
                        else
                        {
                            if (message.Type == (int)MessageTypes.Image)
                            {
                                //delete the files
                                try
                                {
                                    AmazonHelper.Delete(message.ImageFilename); //image
                                    AmazonHelper.Delete(message.ThumbnailFilename); //thumbnail
                                }
                                catch (Exception ex)
                                {
                                    Utils.Log(ex);
                                }
                            }
                            dc.GroupMessages.DeleteOnSubmit(message);
                            dc.SubmitChanges();
                            result.isSuccessful = true;
                            result.errorMessage = "Message deleted.";
                        }
                    }
                    else
                    {
                        result.isSuccessful = false;
                        result.errorMessage = "Message already deleted or you don't have permission to delete it.";
                    }
                }
            }
            catch (Exception)
            {
                result.isSuccessful = false;
                result.errorMessage = "Unexpected error while deleting message.";
            }
            return Json(result);
        }

        private JsonResult UpdateMemberStatus(int groupId, Guid userId, GroupMemberStatuses status)
        {
            var data = new JsonData();
            if (!IsUserAuthenticated)
            {
                data.errorMessage = "You are not logged in.  Please login before you can create a group.";
                data.isSuccessful = false;
                return Json(data);
            }

            var groupViewData = GetGroupViewData(groupId, 0);
            if (!groupViewData.CanManageMembers())
            {
                data.errorMessage = "You are not authorized to manage memebers.";
                data.isSuccessful = false;
                return Json(data);
            }
            try
            {
                Group group;
                string newMemberUserName;
                using (var dc = new YonklyDataContext())
                {
                    var groupMember = dc.GroupMembers.First(mem => mem.GroupId == groupId
                                                                   && mem.UserId == userId);
                    groupMember.Status = (int)status;
                    dc.SubmitChanges();
                    //get group and user info need for sending notification email
                    var info = (from g in dc.Groups
                                where g.Id == groupId
                                select new
                                           {
                                               Group = g,
                                               NewMemberUserName =
                                    g.GroupMembers.Where(gm => gm.UserId == userId).Single().User.UserName
                                           }).Single();
                    group = info.Group;
                    newMemberUserName = info.NewMemberUserName;
                }
                data.errorMessage = "";
                data.isSuccessful = true;

                switch (status)
                {
                    case GroupMemberStatuses.Approved:
                        SendApprovedEmailToJoiner(group, newMemberUserName, System.Web.Security.Membership.GetUser(newMemberUserName).Email);
                        SendNewMemberNotification(group, newMemberUserName);
                        break;
                    case GroupMemberStatuses.Rejected:
                        SendRejectionEmailToJoiner(group);
                        break;
                }

                return Json(data);
            }
            catch (Exception)
            {
                data.errorMessage = "Unknown error while updating group";
                data.isSuccessful = false;
                return Json(data);
            }
        }

        #endregion

        #region Non-Actions

        private bool IsValidUrl(string url)
        {
            if (url.Length < 4)
            {
                return false;
            }
            var groupRoutes = from Route r in RouteTable.Routes
                              where r.Url.ToLower().StartsWith("group")
                              select r;

            foreach (Route route in groupRoutes)
            {
                if (url.ToLower() == route.Defaults["action"].ToString().ToLower())
                {
                    return false;
                }
            }
            return true;
        }

        private GroupConversationViewData GetConversationData(string groupUrl, long messageId, int? page)
        {
            page = page ?? 0;
            var viewData = new GroupConversationViewData(GetBaseViewData(), page) { Id = messageId };
            viewData.IsGroup = true;
            using (var dc = new YonklyDataContext())
            {
                Group g = dc.Groups.Where(group => group.Url.ToLower() == groupUrl.ToLower()).First();
                viewData.GroupInfo = g;
            }
            return viewData;
        }
        protected GroupViewData GetGroupViewData(string groupUrl, int page)
        {
            GroupViewData viewData = new GroupViewData(GetBaseViewData());
            using (var dc = new YonklyDataContext())
            {
                Group g = dc.Groups.Where(group => group.Url.ToLower() == groupUrl.ToLower()).First();
                viewData.GroupInfo = g;
                viewData.Messages = GetGroupMessages(dc, viewData, g, page);
            }

            return viewData;
        }

        protected GroupViewData GetGroupViewData(long groupId, int page)
        {
            GroupViewData viewData = new GroupViewData(GetBaseViewData());
            using (var dc = new YonklyDataContext())
            {
                Group g = dc.Groups.Where(group => group.Id == groupId).First();
                viewData.GroupInfo = g;
                viewData.Messages = GetGroupMessages(dc, viewData, g, page);
            }
            return viewData;
        }

        private PagedList<MessageItem> GetGroupMessages(YonklyDataContext dc,
                                                        BaseViewData viewData, Group group, int page)
        {
            var query = (from message in dc.ViewGroupMessages
                         where message.GroupId == @group.Id
                         select new MessageItem(viewData, message) { CreatedOn = message.CreatedOn }
                        ).OrderByDescending(m => m.CreatedOn);
            return query.ToPagedList(page, Globals.PageSize);
        }

        private bool SendMessageReplyNotification(long groupId, long parentId)
        {
            //try
            //{
            //    const string CacheKey = "GroupReplyNotification";
            //    using (var dc = new YonklyDataContext())
            //    {
            //        var group = dc.Groups.Where(g => g.Id == groupId);
            //        var group
            //    }
            //    var body = HttpContext.Cache[CacheKey] as string;

            //    if (body == null)
            //    {
            //        string file =
            //            System.Web.HttpContext.Current.Server.MapPath("~/content/MailTemplates/GroupReplyNotification.txt");
            //        body = File.ReadAllText(file);

            //        if (HttpContext.Cache[CacheKey] == null)
            //        {
            //            HttpContext.Cache[CacheKey] = body;
            //        }
            //    }

            //    body = body.Replace("<%username%>", parentUserName);
            //    body = body.Replace("<%groupname%>", group.Name);
            //    body = body.Replace("<%groupurl%>", string.Format("{0}/group/{1}", Globals.SiteUrl, group.Url));
            //    body = body.Replace("<%groupsettings%>",
            //                        string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, group.Url));
            //    SendMail(newMemberEmail,
            //             string.Format("Yonkly.com: Welcome to '{0}'", group.Name), body);
            //}
            //catch (Exception ex)
            //{
            //    //ignore email errors
            //    Utils.Log(ex);
            //}
            return false;
        }
        private void SendNewMessageNotification(long groupId, string message, long messageId)
        {
            using (var dc = new YonklyDataContext())
            {
                var groupMembers = (from gm in dc.GroupMembers
                                    where
                                        gm.UserId != LoggedInUserId &&
                                        gm.GroupId == groupId &&
                                        gm.Status == (int)GroupMemberStatuses.Approved &&
                                        gm.NotifyOnMessage
                                    select new
                                    {
                                        GroupUrl = gm.Group.Url,
                                        GroupName = gm.Group.Name,
                                        gm.User.UserName,
                                        gm.User.Membership.Email
                                    });

                const string CacheKey = "GroupMessageNotification";
                foreach (var member in groupMembers)
                {
                    try
                    {
                        var body = HttpContext.Cache[CacheKey] as string;
                        if (body == null)
                        {
                            string file =
                                System.Web.HttpContext.Current.Server.MapPath(
                                    "~/content/MailTemplates/GroupMessageNotification.txt");
                            body = File.ReadAllText(file);

                            if (HttpContext.Cache[CacheKey] == null)
                            {
                                HttpContext.Cache[CacheKey] = body;
                            }
                        }

                        body = body.Replace("<%username%>", member.UserName);
                        body = body.Replace("<%sendername%>", LoggedInUserName);
                        body = body.Replace("<%senderurl%>", string.Format("{0}/{1}", Globals.SiteUrl, LoggedInUserName));
                        body = body.Replace("<%message%>", message);
                        body = body.Replace("<%conversationurl%>", string.Format("{0}/group/{1}/conversation?messageid={2}", Globals.SiteUrl, member.GroupUrl, messageId));

                        body = body.Replace("<%groupname%>", member.GroupName);
                        body = body.Replace("<%groupurl%>",
                                            string.Format("{0}/group/{1}", Globals.SiteUrl, member.GroupUrl));
                        body = body.Replace("<%groupsettings%>",
                                            string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, member.GroupUrl));

                        SendMail(member.Email,
                                 string.Format("Yonkly.com: '{0}' posted new message to '{1}'",
                                               LoggedInUserName, member.GroupName),
                                 body);

                    }
                    catch (Exception ex)
                    {
                        //ignore email errors
                        Utils.Log(ex);
                    }
                }
            }
        }

        private void SendRejectionEmailToJoiner(Group group)
        {
            try
            {
                const string CacheKey = "joinGroupRejection";

                var body = HttpContext.Cache[CacheKey] as string;

                if (body == null)
                {
                    string file =
                        System.Web.HttpContext.Current.Server.MapPath("~/content/MailTemplates/joinGroupRejection.txt");
                    body = File.ReadAllText(file);

                    if (HttpContext.Cache[CacheKey] == null)
                    {
                        HttpContext.Cache[CacheKey] = body;
                    }
                }

                body = body.Replace("<%username%>", LoggedInUserName);
                body = body.Replace("<%groupname%>", group.Name);
                body = body.Replace("<%groupurl%>", string.Format("{0}/group/{1}", Globals.SiteUrl, group.Url));
                body = body.Replace("<%groupsettings%>",
                                    string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, group.Url));
                SendMail(System.Web.Security.Membership.GetUser().Email,
                         string.Format("Yonkly.com: Rejected by Group '{0}'", group.Name), body);
            }
            catch (Exception ex)
            {
                //ignore email errors
                Utils.Log(ex);
            }
        }

        private void SendApprovedEmailToJoiner(Group group, string newMemberUserName, string newMemberEmail)
        {
            try
            {
                const string CacheKey = "joinGroupToJoiner";

                var body = HttpContext.Cache[CacheKey] as string;

                if (body == null)
                {
                    string file =
                        System.Web.HttpContext.Current.Server.MapPath("~/content/MailTemplates/joinGroupToJoiner.txt");
                    body = File.ReadAllText(file);

                    if (HttpContext.Cache[CacheKey] == null)
                    {
                        HttpContext.Cache[CacheKey] = body;
                    }
                }

                body = body.Replace("<%username%>", newMemberUserName);
                body = body.Replace("<%groupname%>", group.Name);
                body = body.Replace("<%groupurl%>", string.Format("{0}/group/{1}", Globals.SiteUrl, group.Url));
                body = body.Replace("<%groupsettings%>",
                                    string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, group.Url));
                SendMail(newMemberEmail,
                         string.Format("Yonkly.com: Welcome to '{0}'", group.Name), body);
            }
            catch (Exception ex)
            {
                //ignore email errors
                Utils.Log(ex);
            }
        }

        private void SendNewMemberNotification(Group g, string newMemberUserName)
        {
            using (var dc = new YonklyDataContext())
            {
                var groupMembers = (from gm in dc.GroupMembers
                                    where
                                        gm.UserId != LoggedInUserId &&
                                        gm.User.UserName.ToLower() != newMemberUserName.ToLower() &&
                                        gm.GroupId == g.Id &&
                                        gm.Status == (int)GroupMemberStatuses.Approved &&
                                        gm.NotifyOnJoin
                                    select new
                                               {
                                                   GroupUrl = gm.Group.Url,
                                                   GroupName = gm.Group.Name,
                                                   gm.User.UserName,
                                                   gm.User.Membership.Email
                                               });

                const string CacheKey = "joinGroupToMembers";
                foreach (var member in groupMembers)
                {
                    try
                    {
                        var body = HttpContext.Cache[CacheKey] as string;
                        if (body == null)
                        {
                            string file =
                                System.Web.HttpContext.Current.Server.MapPath(
                                    "~/content/MailTemplates/joinGroupToMembers.txt");
                            body = File.ReadAllText(file);

                            if (HttpContext.Cache[CacheKey] == null)
                            {
                                HttpContext.Cache[CacheKey] = body;
                            }
                        }

                        body = body.Replace("<%username%>", member.UserName);
                        body = body.Replace("<%groupname%>", member.GroupName);
                        body = body.Replace("<%groupurl%>",
                                            string.Format("{0}/group/{1}", Globals.SiteUrl, member.GroupUrl));
                        body = body.Replace("<%groupsettings%>",
                                            string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, member.GroupUrl));

                        body = body.Replace("<%newuser%>", newMemberUserName);
                        body = body.Replace("<%newuserurl%>", string.Format("{0}/{1}", Globals.SiteUrl, newMemberUserName));

                        SendMail(member.Email,
                                 string.Format("Yonkly.com: '{0}' joined group '{1}'",
                                               newMemberUserName, member.GroupName),
                                 body);

                    }
                    catch (Exception ex)
                    {
                        //ignore email errors
                        Utils.Log(ex);
                    }
                }
            }
        }

        private void SendMemberLeaveNotification(long groupId, Guid userId)
        {
            using (var dc = new YonklyDataContext())
            {
                var groupMembers = (from gm in dc.GroupMembers
                                    where
                                        gm.UserId != LoggedInUserId &&
                                        gm.UserId != userId &&
                                        gm.GroupId == groupId &&
                                        gm.Status == (int)GroupMemberStatuses.Approved &&
                                        gm.NotifyOnLeave
                                    select new
                                    {
                                        GroupUrl = gm.Group.Url,
                                        GroupName = gm.Group.Name,
                                        gm.User.UserName,
                                        gm.User.Membership.Email
                                    });
                var oldMemberName = dc.Users.Where(u => u.UserId == userId).First().UserName;

                const string CacheKey = "leaveGroupToMembers";
                foreach (var member in groupMembers)
                {
                    try
                    {
                        var body = HttpContext.Cache[CacheKey] as string;
                        if (body == null)
                        {
                            string file =
                                System.Web.HttpContext.Current.Server.MapPath(
                                    "~/content/MailTemplates/leaveGroupToMembers.txt");
                            body = File.ReadAllText(file);

                            if (HttpContext.Cache[CacheKey] == null)
                            {
                                HttpContext.Cache[CacheKey] = body;
                            }
                        }

                        body = body.Replace("<%username%>", member.UserName);
                        body = body.Replace("<%groupname%>", member.GroupName);
                        body = body.Replace("<%groupurl%>",
                                            string.Format("{0}/group/{1}", Globals.SiteUrl, member.GroupUrl));
                        body = body.Replace("<%groupsettings%>",
                                            string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, member.GroupUrl));

                        body = body.Replace("<%newuser%>", oldMemberName);
                        body = body.Replace("<%newuserurl%>", string.Format("{0}/{1}", Globals.SiteUrl, oldMemberName));

                        SendMail(member.Email,
                                 string.Format("Yonkly.com: '{0}' left group '{1}'",
                                               oldMemberName, member.GroupName),
                                 body);

                    }
                    catch (Exception ex)
                    {
                        //ignore email errors
                        Utils.Log(ex);
                    }
                }
            }
        }

        private void SendPendingApprovalNotification(Group group, string newMemberUserName)
        {
            try
            {
                const string CacheKey = "PendingApprovalNotification";

                var body = HttpContext.Cache[CacheKey] as string;
                string ownerName, ownerEmail;
                using (var dc = new YonklyDataContext())
                {
                    var query = from gm in dc.GroupMembers
                                where gm.GroupId == @group.Id
                                && gm.Role == (int)GroupMemberRoles.Owner
                                select new
                                           {
                                               gm.User.UserName,
                                               gm.User.Membership.Email
                                           };
                    var owner = query.First();
                    ownerEmail = owner.Email;
                    ownerName = owner.UserName;
                }
                if (body == null)
                {
                    string file =
                        System.Web.HttpContext.Current.Server.MapPath("~/content/MailTemplates/PendingApprovalNotification.txt");
                    body = File.ReadAllText(file);

                    if (HttpContext.Cache[CacheKey] == null)
                    {
                        HttpContext.Cache[CacheKey] = body;
                    }
                }

                body = body.Replace("<%username%>", ownerName);
                body = body.Replace("<%groupname%>", group.Name);
                body = body.Replace("<%groupurl%>", string.Format("{0}/group/{1}", Globals.SiteUrl, group.Url));
                body = body.Replace("<%groupsettings%>",
                                    string.Format("{0}/group/{1}/mysettings", Globals.SiteUrl, group.Url));

                body = body.Replace("<%newuser%>", newMemberUserName);
                body = body.Replace("<%newuserurl%>", string.Format("{0}/{1}", Globals.SiteUrl, newMemberUserName));

                SendMail(ownerEmail,
                         string.Format("Yonkly.com: '{0}' requests to join '{1}'", newMemberUserName, group.Name), body);
            }
            catch (Exception ex)
            {
                //ignore email errors
                Utils.Log(ex);
            }
        }
        #endregion
    }
}